package com.ygqh.baby.utils;

import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * 邀请码生成器，算法原理：
 * 1) 获取id: XXXXXX
 * 2) 使用自定义进制转为：gpm6
 * 3) 转为字符串，并在后面加'O'字符：gpm6o
 * 4）在后面随机产生若干个随机数字字符：gpm6o7
 * 转为自定义进制后就不会出现o这个字符，然后在后面加个'o'，这样就能确定唯一性。最后在后面产生一些随机字符进行补全。
 *
 * 动态邀请码，多用于隐私邀请码
 *
 * @Author: sunshuo
 * @Date: 2019/3/28 18:04
 * @Version: 1.0
 */
public class ShareCodeUtil {

	/**
	 * 自定义进制(0,1没有加入,容易与o,l混淆)
	 */
	private static final char[] r = new char[]{'7', 'P', '5', 'I', 'K', '3', 'M', 'J', 'U',
			'F', 'R','Q', 'W', 'E', '8', 'A', 'S', '2', 'D', 'Z', 'X', '9', 'C', '4', 'V',
			'B', 'G', 'H', 'Y', 'L', 'T', '6', 'N'};

	/**
	 * (不能与自定义进制有重复)
	 */
	private static final char b = 'O';

	/**
	 * 进制长度
	 */
	private static final int binLen = r.length;

	/**
	 * 序列最小长度
	 */
	private static final int s = 6;

	public static String toSerialCode(long id) {
		return toSerialCode(id, false);
	}

	/**
	 * 根据ID生成随机码
	 *
	 * @param id ID
	 * @param dynamic 是否生成动态码
	 * @return 随机码
	 */
	public static String toSerialCode(long id, boolean dynamic) {
		char[] buf = new char[32];
		int charPos = 32;
		while ((id / binLen) > 0) {
			int ind = (int) (id % binLen);
			buf[--charPos] = r[ind];
			id /= binLen;
		}
		buf[--charPos] = r[(int) (id % binLen)];
		String str = new String(buf, charPos, (32 - charPos));
		// 不够长度的自动补全
		if (str.length() < s) {
			StringBuilder sb = new StringBuilder();
			sb.append(b);
			Random rnd = new Random();
			for (int i = 1; i < (s - str.length()); i++) {
				int index = dynamic ? rnd.nextInt(binLen) : (i - 1);
				sb.append(r[index]);
			}
			str += sb.toString();
		}
		return str;
	}

	/**
	 * 随机码还原成ID
	 *
	 * @param code 随机码
	 * @return ID
	 */
	public static long codeToId(String code) throws Exception {
		if (StringUtils.isBlank(code) || code.length() != s) {
			throw new Exception("邀请码异常");
		}
		char[] chs = code.toUpperCase().toCharArray();
		long res = 0L;
		for (int i = 0; i < chs.length; i++) {
			int ind = 0;
			for (int j = 0; j < binLen; j++) {
				if (chs[i] == r[j]) {
					ind = j;
					break;
				}
			}
			if (chs[i] == b) {
				break;
			}
			if (i > 0) {
				res = res * binLen + ind;
			} else {
				res = ind;
			}
		}
		return res;
	}

	public static void main(String[] args) throws Exception {
		List<String> list = Arrays.asList("5ORHU5","35K4OW","5O8IM5","KWUXOK","5O4WKI","5O58ZH","5OE6QI","MJJ8OM","5OQM99","NKNONF","5O9U5A","5OZDAS","DQOY3Z","5OCLRC","5OTR5E","PWPBOF","J7OLVL","KQ4VOM","63AORH","PIAVOC","5OIJAQ","DQOWJM","55JFOC","3M6BO4","54IEOT","5O68IW","DQO8HU","IEBKOC","BLJOGR","5O65IZ","IY4ZOA","VP3OEH","IZJSOJ","IZVPOV","KS2WOD","PBDBOB","5OM868","5SPUO3","GILOEU","52HRO3","5OIFME","5ORARC","I2H7OB","TIDOWV","3GKWOX","P2SNOQ","PI4EOY","5O3GLS","NU9OT5","PKHPOZ","DQON2A","PPXWOH","K2G2O2","JWFDOI","3PJ8OG","5OZE9P","KZUVOQ","3KVIO3","P5SIO4","DQO2C9","PJU4O3","KZVQOQ","59BQOJ","LNHOPX","IKB5OX","3KVIOK","KMIQOC","5OY4MK","P45KOS","5OUPH9","5OQUH9","3645O9","IB9HOM","P5SIOV","P2ENON","5REAOW","IQV2OW","J7OT2W","MEEFOD","Sanni ","3TGHOD","KUGXO7","P5SIOX","DQOR5M","5OPH7C","I6ISOV","3I9AO7","MD3NO7","JW2YOP","5O7P5I","ZO7P5I","3XTWO9","59IGO7","J7O3SH","IMIBO7","MD3NOK","DQO7P5","NLXOPR","5REAO7","I4JAO7","JEVYO7","5MGAO7","I5S7OX");
		System.out.println("list size: " + list.size());
		/*for (String code : list) {
			System.out.println(codeToId(code));
		}*/

		List<String> newList = new ArrayList<>();
		for (String code : list) {
			if(codeToId(code) == 202467) {
				newList.add(code);
			}
		}
		System.out.println(newList);
		/*List<String> list = new ArrayList<>();
		int mul = 0;
		for (int i = 1; i <= 1000000; i++) {
			String code = toSerialCode(i);
			if (list.contains(code)) {
				mul++;
				continue;
			}
			list.add(code);
			System.out.println(code);
		}
		System.out.println(mul);
		System.out.println(list.size());*/
		/*System.out.println(toSerialCode(202467L)); // 3XTWO7
		System.out.println(toSerialCode(202467L)); // 3XTWO7
		System.out.println(toSerialCode(202467L, true)); // 3XTWOE
		System.out.println(toSerialCode(202467L, true)); // 3XTWOE*/
		/*String tempCode = "3XTWO7";
		for (int i = 1; i <= 100000; i++) {
			String code = toSerialCode(202467L);
			if (!code.equals(tempCode)) {
				System.out.println(code);
			}
		}*/
//		System.out.println(codeToId("5O7P5I"));
	}
}
